package com.my.customloading;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.OvershootInterpolator;

/**
 * Created by 张英杰 on 2016/9/18.
 */
public class SplashView extends View {

    //大圆(里面包含很多小圆)半径
    private float mRotationRadius = 180;
    //小圆半径
    private float mCircleRadius = 36;
    // 小圆圈的颜色列表，在initialize方法里面初始化
    private int[] mCircleColors;
    // 大圆和小圆旋转的时间
    private long mRotationDuration = 1200; // ms
    // 第二部分动画的执行总时间(包括三个动画时间，各占1/3)
    private long mSplashDuration = 1200; // ms
    // 整体的背景颜色
    private int mSplashBgColor = Color.WHITE;
    /**
     * 参数，保存了一些绘制状态，会被动态地改变*
     */
    // 空心圆初始半径
    private float mHoleRadius = 0f;
    //当前大圆旋转角度(弧度)
    private float mCurrentRotationAngle = 0f;
    //当前大圆半径
    private float mCurrentRotationRadius;
    //当前单圆的半径
    private float mCurrentSingleCircleRadius;
    // 保存当前动画状态--当前在执行哪种动画
    private SplashState mState = null;
    // 绘制圆的画笔
    private Paint mPaint = new Paint();
    // 绘制背景的画笔
    private Paint mPaintBackground = new Paint();
    // 屏幕正中心点坐标
    private float mCenterX;
    private float mCenterY;
    // 屏幕对角线一半
    private float mDiagonalDist;
    //动画执行的时间(系统时间 ms)draw时间
    double d1, d2, d3, d4;

    public SplashView(Context context) {
        super(context);
        //初始化
        initialize(context);
    }

    /**
     * 定义一个抽象类--动画状态类 作用：让几个动画状态类开始执行后都开始绘制各自的界面--invalidate--》onDraw（）
     * 通过onDraw方法统一控制调用drawstate方法来绘制界面
     */
    private abstract class SplashState {
        public abstract void drawState(Canvas canvas);

    }

    private void initialize(Context context) {
        // 色值数组
        mCircleColors = context.getResources().getIntArray(R.array.splash_circle_colors);
        // 给SplashView设置一个默认的背景--透明
        setBackgroundColor(Color.TRANSPARENT);
        // 设置画笔
        // 消除锯齿
        mPaint.setAntiAlias(true);
        mPaintBackground.setAntiAlias(true);
        // STROKE描边，空心效果
        mPaintBackground.setStyle(Paint.Style.STROKE);
        // 设置默认背景颜色颜色（背景画笔设置默认设置，Color.WHITE）
        mPaintBackground.setColor(mSplashBgColor);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        mDiagonalDist = (float) (Math.sqrt(w * w + h * h) / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //ondraw 为不停绘制 刷屏 每帧。。。毫秒
//        Log.i("onDraw===", (mState == null)+ "====" + System.currentTimeMillis());
        // canvas画布，paint画笔
        if (mState == null) {
            // 第一次执行的动画
            handleFirstDraw();
        }
//        Log.i("onDraw===22", mState.getClass().getName().toString() + "====" + System.currentTimeMillis());
        // 分发到各个动画状态类---绘制各自的图像
        mState.drawState(canvas);
    }

    //暴露的方法，其余动画的入口）
    //执行第二部分的动画然后消失，显示contentview
    public void splashDisapper() {
        // mState不为null，并且是第一个动画实例
        if (mState != null && mState instanceof RotationState) {
            RotationState rs = (RotationState) mState;
            rs.cancel();// 停止旋转动画
            // 开始下一个动画（聚合动画）
            // 开线程放到消息队列里面，为了不影响主UI线程的响应
            post(new Runnable() { //post ???
                @Override
                public void run() {
                    mState = new MergingState();
                }
            });
        }
    }

    //绘制大圆背景
    private void drawBackground(Canvas canvas) {
        // 绘制splashview的背景
        if (mHoleRadius > 0f) {
            /**
             * 绘制空心圆的技巧
             */
            float strokeWidth = mDiagonalDist - mHoleRadius;// 屏幕对角线一半 空心圆初始半径0F
            float circleRadius = mHoleRadius + strokeWidth / 2;// 空心圆初始半径

            // 绘制边框（width）--里面是空心的
            mPaintBackground.setStrokeWidth(strokeWidth);
            // 原点：屏幕中心点 半径：屏幕对角线一半的一半 背景画笔：mPaintBackground
            canvas.drawCircle(mCenterX, mCenterY, circleRadius,
                    mPaintBackground);
//            canvas.drawCircle(300, 300, 100, mPaintBackground);             //绘制圆
//            canvas.drawLine(50, 50, 450, 50, mPaintBackground);            //绘制直线
//            canvas.drawRect(100, 100, 200, 600, mPaintBackground);         //绘制矩形
//            Log.i("++++", "R==" + circleRadius + "笔宽度===" + strokeWidth + "对角线==" + mDiagonalDist + "空心圆初始化半径==" + mHoleRadius);
        } else {
            canvas.drawColor(mSplashBgColor);
        }
    }

    //绘制里面的小圆
    private void drawCircles(Canvas canvas) {
        // 绘制小圆 --遍历6个小圆
        int numCircles = mCircleColors.length;//色值数组大小
        // 小圆之间的间隔角度 360/6就是每个小圆的夹角大小
        float rotationAngle = (float) (2 * Math.PI / numCircles);
        for (int i = 0; i < numCircles; i++) {
            // 得到某个小圆的坐标
            // 每一个小圆的弧度 = 当前大圆整体旋转了多少度 + i*小圆之间的间隔角度
            double angle = mCurrentRotationAngle + (i * rotationAngle);
            // 下面计算小圆在弧度不断改变的情况下，圆心的坐标位置
            double circleX = mCenterX + mCurrentRotationRadius * Math.cos(angle);
            double circleY = mCenterY + mCurrentRotationRadius * Math.sin(angle);
            // 设置颜色
            mPaint.setColor(mCircleColors[i]);
            // 根据小圆的坐标点绘制小圆
            canvas.drawCircle((float) circleX, (float) circleY, mCircleRadius,
                    mPaint);
        }
    }

    //第一次执行的动画，设置默认执行的动画对象
    private void handleFirstDraw() {
        //默认执行一次第一个旋转动画，给mState赋值
        mState = new RotationState();
        // 第一次执行动画，需要出示一些默认参数
        // 大圆当前旋转角度
        mCurrentRotationAngle = 0f;
        // 设置默认的空心圆的半径
        mHoleRadius = 0f;
        // 默认设置当前大圆的半径
        mCurrentRotationRadius = mRotationRadius;
        // 默认设置当前单圆半径
        mCurrentSingleCircleRadius = mCircleRadius;
    }

    //定义第一个动画---旋转动画 大圆（ 包含了6个小圆） （继承抽象类的子类，其中把drawState方法写好，等待onDraw调用方法）
    private class RotationState extends SplashState {
        private ValueAnimator mAnimator;// 属性动画

        /**
         * 构造方法
         */
        public RotationState() {
            //圆心角弧度变化 0 ——360
            mAnimator = ValueAnimator.ofFloat(0, (float) (Math.PI * 2));
            mAnimator.setDuration(mRotationDuration);// 设置默认的旋转时间 1200ms
            // 使用线性插值器LinearInterpolator可以让动画平滑地执行
//            AccelerateDecelerateInterpolator   在动画开始与介绍的地方速率改变比较慢，在中间的时候加速
//            AccelerateInterpolator                     在动画开始的地方速率改变比较慢，然后开始加速
//            AnticipateInterpolator                      开始的时候向后然后向前甩
//            AnticipateOvershootInterpolator     开始的时候向后然后向前甩一定值后返回最后的值
//            BounceInterpolator                          动画结束的时候弹起
//            CycleInterpolator                             动画循环播放特定的次数，速率改变沿着正弦曲线
//            DecelerateInterpolator                    在动画开始的地方快然后慢
//            LinearInterpolator                            以常量速率改变
//            OvershootInterpolator                      向前甩一定值后再回到原来位置
            mAnimator.setInterpolator(new LinearInterpolator());
            // 设置监听
            mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    // 当前大圆旋转角度(弧度)
                    mCurrentRotationAngle = (float) valueAnimator.getAnimatedValue();
                    // 刷新界面，重新绘制界面--onDraw
                    invalidate();
                }
            });
            // 重复次数为无穷
            mAnimator.setRepeatCount(ValueAnimator.INFINITE);
            // 设置让他不断地旋转 --循环
            mAnimator.setRepeatMode(ValueAnimator.RESTART);
            // 开始执行
            mAnimator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            d1 = System.currentTimeMillis();
            Log.i("time===", "d1开始====" + System.currentTimeMillis());
            // 绘制界面--根据旋转情况来绘制界面---坐标！时间！
            // 绘制背景
            drawBackground(canvas);
            // 绘制里面的小圆
            drawCircles(canvas);
        }

        public void cancel() {
            mAnimator.cancel();
        }
    }

    //定义第二个动画---6个小圆聚合动画
    private class MergingState extends SplashState {

        public MergingState() {
            // 聚合范围：0~大圆的半径 0~90
            final ValueAnimator animator = ValueAnimator.ofFloat(0, mRotationRadius);
            animator.setDuration(mSplashDuration / 3);
            // 设置监听
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    // 当前大圆的旋转半径（当前半径对象，可变）
                    mCurrentRotationRadius = (float) animator.getAnimatedValue();
                    postInvalidate();//与invalidate()的区别？？？
                }
            });
            // 设置监听--
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    // 动画结束--进入下一个动画 3（中心圆再缩放一下）
                    mState = new SingularityState();
                }
            });
            // 插值器（Interpolator）弹射的效果，注意：缩放动画就是因为这个属性会先变大一下再缩小
            animator.setInterpolator(new OvershootInterpolator(6f));
            // 保持动画执行后的状态
            animator.reverse();
        }

        @Override
        public void drawState(Canvas canvas) {
            d2 = System.currentTimeMillis();
            Log.i("time===", "d2开始====" + (d2 - d1));
            // 绘制界面--根据旋转情况来绘制界面---坐标！时间！
            // 背景绘制
            drawBackground(canvas);
            // 处理小圆
            drawCircles(canvas);
        }
    }

    //定义第三个动画---（为了更加美观，最好处理一下缩放后，中心点的圆再进行缩放） 中心点位置单独的圆的缩放动画效果
    private class SingularityState extends SplashState {

        public SingularityState() {
            // 0~单圆的半径 0~18
            final ValueAnimator animator = ValueAnimator.ofFloat(0, mCircleRadius);
            animator.setDuration(mSplashDuration / 3);
            // 插值器（Interpolator）弹射的效果，注意：缩放动画就是因为这个属性会先变大一下再缩小
//            animator.setInterpolator(new OvershootInterpolator(6f));
            animator.setInterpolator(new LinearInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    // 单圆的半径
                    mCurrentSingleCircleRadius = (float) animator.getAnimatedValue();
                    invalidate();
                }
            });
            // 监听
            animator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    // 执行下一个动画，动画4，扩散动画
                    mState = new ExpandingState();
                }
            });
            animator.reverse();
        }

        @Override
        public void drawState(Canvas canvas) {
            d3 = System.currentTimeMillis();
            Log.i("time===", "d3开始====" + (d3 - d2));
            // 绘制界面--根据旋转情况来绘制界面---坐标！时间！
            drawBackground(canvas);
            // 画单圆
            drawSingleCircle(canvas);
        }
    }

    //定义第四个动画--- 空心圆动画
    private class ExpandingState extends SplashState {

        public ExpandingState() {
            final ValueAnimator animator = ValueAnimator.ofFloat(0, mDiagonalDist);
            //减速效果  (在动画开始的地方快然后慢)
            animator.setInterpolator(new DecelerateInterpolator());
            animator.setDuration(mSplashDuration / 3);
//            animator.setDuration(4000);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator valueAnimator) {
                    mHoleRadius = (float) animator.getAnimatedValue();
                    invalidate();
                }
            });
            animator.start();
        }

        @Override
        public void drawState(Canvas canvas) {
            d4 = System.currentTimeMillis();
            Log.i("time===", "d4开始====" + (d4 - d3));
            // 绘制界面--根据旋转情况来绘制界面---坐标！时间！
            drawBackground(canvas);
        }
    }

    //画单圆
    private void drawSingleCircle(Canvas canvas) {
        mPaint.setColor(mCircleColors[1]);// 中心圆的背景颜色值
        canvas.drawCircle(mCenterX, mCenterY, mCurrentSingleCircleRadius, mPaint);
    }
}
